import { Injectable, Logger } from '@nestjs/common';
import { RedisService } from '../../auth/redis/redis.service';

@Injectable()
export class SmsService {
  private readonly logger = new Logger(SmsService.name);
  private readonly VERIFICATION_CODE_PREFIX = 'verification_code:';
  private readonly VERIFICATION_CODE_ATTEMPTS_PREFIX = 'verification_code_attempts:';
  private readonly CODE_EXPIRY_SECONDS = 300; // 5 minutes
  private readonly MAX_ATTEMPTS_PER_HOUR = 3;
  private readonly ATTEMPTS_EXPIRY_SECONDS = 3600; // 1 hour

  constructor(private readonly redisService: RedisService) {}

  async sendVerificationCode(phone: string): Promise<void> {
    // Check rate limiting
    const attempts = await this.getAttempts(phone);
    if (attempts >= this.MAX_ATTEMPTS_PER_HOUR) {
      throw new Error('Too many attempts. Please try again later.');
    }

    // Generate a random 6-digit code
    const code = Math.floor(100000 + Math.random() * 900000).toString();

    // Store the code in Redis with expiration
    await this.redisService.set(this.getVerificationCodeKey(phone), code, this.CODE_EXPIRY_SECONDS);

    // Increment attempts counter
    await this.incrementAttempts(phone);

    // In production, integrate with actual SMS service
    // For now, just log the code
    this.logger.debug(`Verification code for ${phone}: ${code}`);
  }

  async verifyCode(phone: string, code: string): Promise<boolean> {
    const storedCode = await this.redisService.get(this.getVerificationCodeKey(phone));

    if (!storedCode) {
      return false;
    }

    const isValid = storedCode === code;

    if (isValid) {
      // Delete the code after successful verification to prevent reuse
      await this.redisService.del(this.getVerificationCodeKey(phone));
    }

    return isValid;
  }

  private getVerificationCodeKey(phone: string): string {
    return `${this.VERIFICATION_CODE_PREFIX}${phone}`;
  }

  private getAttemptsKey(phone: string): string {
    return `${this.VERIFICATION_CODE_ATTEMPTS_PREFIX}${phone}`;
  }

  private async getAttempts(phone: string): Promise<number> {
    const attempts = await this.redisService.get(this.getAttemptsKey(phone));
    return attempts ? parseInt(attempts, 10) : 0;
  }

  private async incrementAttempts(phone: string): Promise<void> {
    const key = this.getAttemptsKey(phone);
    const attempts = await this.getAttempts(phone);

    await this.redisService.set(key, (attempts + 1).toString(), this.ATTEMPTS_EXPIRY_SECONDS);
  }
}
